package mcps

import (
	"context"
	"fmt"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	"github.com/shirou/gopsutil/disk"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func FileSystemMCPServer() {
	s := server.NewMCPServer(
		"文件系统监控工具",
		"1.0.0",
	)

	// 添加磁盘使用情况工具
	diskUsageTool := mcp.NewTool("disk_usage",
		mcp.WithDescription("获取磁盘使用情况"),
		mcp.WithString("path",
			mcp.Description("指定路径，默认为所有分区"),
		),
	)

	// 添加目录大小统计工具
	dirSizeTool := mcp.NewTool("dir_size",
		mcp.WithDescription("统计目录大小"),
		mcp.WithString("dir_path",
			mcp.Required(),
			mcp.Description("目录路径"),
		),
		mcp.WithString("exclude",
			mcp.Description("排除的文件或目录模式，多个用逗号分隔"),
		),
	)

	// 添加文件变化监控工具
	fileMonitorTool := mcp.NewTool("file_monitor",
		mcp.WithDescription("监控目录下的文件变化"),
		mcp.WithString("dir_path",
			mcp.Required(),
			mcp.Description("监控的目录路径"),
		),
		mcp.WithString("duration",
			mcp.Description("监控持续时间（如：30s, 1m, 5m），默认为1分钟"),
		),
	)

	// 添加工具处理函数
	s.AddTool(diskUsageTool, diskUsageHandler)
	s.AddTool(dirSizeTool, dirSizeHandler)
	s.AddTool(fileMonitorTool, fileMonitorHandler)

	// 启动服务器
	fmt.Println("文件系统监控服务已启动...")
	if err := server.ServeStdio(s); err != nil {
		fmt.Printf("服务器错误: %v\n", err)
	}
}

func diskUsageHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	// 获取指定路径
	path, _ := request.Params.Arguments["path"].(string)

	// 获取分区信息
	var partitions []disk.PartitionStat
	var err error
	if path != "" {
		// 获取指定路径的分区信息
		partitions = []disk.PartitionStat{{
			Mountpoint: path,
		}}
	} else {
		// 获取所有分区信息
		partitions, err = disk.Partitions(true)
		if err != nil {
			return mcp.NewToolResultError(fmt.Sprintf("获取分区信息失败: %v", err)), nil
		}
	}

	// 格式化输出
	var result strings.Builder
	result.WriteString("===== 磁盘使用情况 =====\n\n")

	for _, partition := range partitions {
		usage, err := disk.Usage(partition.Mountpoint)
		if err != nil {
			continue
		}

		// 只显示总容量大于1GB的分区
		if usage.Total < 1024*1024*1024 {
			continue
		}

		result.WriteString(fmt.Sprintf("分区: %s\n", partition.Mountpoint))
		result.WriteString(fmt.Sprintf("  文件系统: %s\n", partition.Fstype))
		result.WriteString(fmt.Sprintf("  总容量: %.2f GB\n", float64(usage.Total)/(1024*1024*1024)))
		result.WriteString(fmt.Sprintf("  已用空间: %.2f GB\n", float64(usage.Used)/(1024*1024*1024)))
		result.WriteString(fmt.Sprintf("  可用空间: %.2f GB\n", float64(usage.Free)/(1024*1024*1024)))
		result.WriteString(fmt.Sprintf("  使用率: %.2f%%\n", usage.UsedPercent))
		result.WriteString("\n")
	}

	return mcp.NewToolResultText(result.String()), nil
}

func dirSizeHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	// 获取目录路径
	dirPath, ok := request.Params.Arguments["dir_path"].(string)
	if !ok || dirPath == "" {
		return mcp.NewToolResultError("dir_path 参数必须是非空字符串"), nil
	}

	// 获取排除模式
	exclude, _ := request.Params.Arguments["exclude"].(string)
	excludePatterns := strings.Split(exclude, ",")
	for i := range excludePatterns {
		excludePatterns[i] = strings.TrimSpace(excludePatterns[i])
	}

	// 格式化输出
	var result strings.Builder
	result.WriteString(fmt.Sprintf("===== 目录大小统计 =====\n"))
	result.WriteString(fmt.Sprintf("目录: %s\n", dirPath))
	if exclude != "" {
		result.WriteString(fmt.Sprintf("排除: %s\n", exclude))
	}
	result.WriteString("\n")

	// 统计大小
	var totalSize int64
	var fileCount, dirCount int

	err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 检查是否在排除列表中
		for _, pattern := range excludePatterns {
			if pattern != "" {
				matched, err := filepath.Match(pattern, filepath.Base(path))
				if err == nil && matched {
					if info.IsDir() {
						return filepath.SkipDir
					}
					return nil
				}
			}
		}

		if info.IsDir() {
			dirCount++
		} else {
			fileCount++
			totalSize += info.Size()
		}

		return nil
	})

	if err != nil {
		return mcp.NewToolResultError(fmt.Sprintf("统计失败: %v", err)), nil
	}

	result.WriteString(fmt.Sprintf("总大小: %.2f MB\n", float64(totalSize)/(1024*1024)))
	result.WriteString(fmt.Sprintf("文件数: %d\n", fileCount))
	result.WriteString(fmt.Sprintf("目录数: %d\n", dirCount))

	return mcp.NewToolResultText(result.String()), nil
}

func fileMonitorHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	// 获取目录路径
	dirPath, ok := request.Params.Arguments["dir_path"].(string)
	if !ok || dirPath == "" {
		return mcp.NewToolResultError("dir_path 参数必须是非空字符串"), nil
	}

	// 获取监控持续时间
	duration := "1m"
	if d, ok := request.Params.Arguments["duration"].(string); ok && d != "" {
		duration = d
	}

	// 解析持续时间
	d, err := time.ParseDuration(duration)
	if err != nil {
		return mcp.NewToolResultError("无效的持续时间格式"), nil
	}

	// 格式化输出
	var result strings.Builder
	result.WriteString(fmt.Sprintf("===== 文件变化监控 =====\n"))
	result.WriteString(fmt.Sprintf("监控目录: %s\n", dirPath))
	result.WriteString(fmt.Sprintf("监控时长: %s\n\n", duration))

	// 记录初始状态
	initialState := make(map[string]os.FileInfo)
	err = filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		initialState[path] = info
		return nil
	})

	if err != nil {
		return mcp.NewToolResultError(fmt.Sprintf("获取初始状态失败: %v", err)), nil
	}

	// 开始监控
	start := time.Now()
	for time.Since(start) < d {
		// 获取当前状态
		currentState := make(map[string]os.FileInfo)
		err = filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			currentState[path] = info
			return nil
		})

		if err != nil {
			continue
		}

		// 检查变化
		for path, currentInfo := range currentState {
			if initialInfo, exists := initialState[path]; !exists {
				// 新文件
				result.WriteString(fmt.Sprintf("%s 新建: %s\n", time.Now().Format("15:04:05"), path))
			} else if currentInfo.ModTime() != initialInfo.ModTime() {
				// 修改的文件
				result.WriteString(fmt.Sprintf("%s 修改: %s\n", time.Now().Format("15:04:05"), path))
			}
		}

		for path := range initialState {
			if _, exists := currentState[path]; !exists {
				// 删除的文件
				result.WriteString(fmt.Sprintf("%s 删除: %s\n", time.Now().Format("15:04:05"), path))
			}
		}

		initialState = currentState
		time.Sleep(time.Second)
	}

	return mcp.NewToolResultText(result.String()), nil
}
